import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;

/**
 * A graphical user interface for a chat application.
 * @author Peter Sundqvist
 */
public class ChatGUI extends JFrame
{
	private ChatInterface m_interface;
	
	// Tabs
	private JTabbedPane m_tabs;
	private JPanel m_nameServerPanel;
	private JPanel m_chatPanel;
	
	// Name server panel content
	private JToolBar m_nsToolBar;
	private JTextField m_nsHost;
	private JTextField m_nsPort;
	private JLabel m_nsHostText;
	private JLabel m_nsPortText;
	private JButton m_nsConnectBtn;
	private JScrollPane m_nsScroll;
	private JList m_serverList;
	private JPanel m_serverConnectPanel;
	private JTextField m_nickname;
	private JLabel m_nicknameText;
	private JButton m_serverConnectBtn;

	// Chat panel content
	private JToolBar m_chatToolBar;
	private JCheckBox m_encrypt;
	private JCheckBox m_compress;
	private JTextField m_cryptKey;
	private JLabel m_cryptKeyText;
	private JButton m_disconnectBtn;
	private JEditorPane m_output; // Where messages are pritned
	private JScrollPane m_scrollOutput;
	private JList m_clientList;
	private JScrollPane m_scrollClientList;
	private JPanel m_sendPanel;
	private JTextField m_input; // Input for message to send
	private JButton m_sendBtn;
	private String m_text = ""; // Chat server text
	
	private boolean m_useNameServer;

	/**
	 * Create a new chat.
	 * @param name - the name in the title bar for the chat window.
	 * @param ci - the chat interface which will be called on GUI actions.
	 * @param useNameServer - true if the chat client uses a name server to find chat servers
	 * @param useEncrypt - true if the chat client uses encryption/compression
	 */
	public static void create(final String name, final ChatInterface ci) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() { new ChatGUI(name,ci); }
		});
	}

	/**
	 * Set the list of servers to show up under the name server tab.
	 * The list should not be changed after sent to the GUI.
	 * @param servers - short descriptive texts for all available servers
	 */
	public void setServerList(final String[] servers) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() { m_serverList.setListData(servers); }
		});
	}

	/**
	 * Enable or disable the chat tab.
	 * @param value - true if enabled, false otherwise
	 */
	public void setChatEnabled(final boolean value) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() { m_tabs.setEnabledAt(1,value); }
		});	
	}

	/**
	 * Set the title of the chat tab.
	 * Don't alter the supplied string after a call to this method.
	 * @param title - the text to show on the chat tab
	 */
	public void setChatTitle(final String title) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() { m_tabs.setTitleAt(1,title); }
		});	
	}

	/**
	 * Set which tab to show.
	 * @param index -	0 is the name server tab
	 *					1 is the chat tab
	 */
	public void setSelectedTab(final int index) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() { m_tabs.setSelectedIndex(index); }
		});	
	}

	/**
	 * Set which nicknames to show in the client list.
	 * The list should not be altered after a call to this method.
	 * @param clients - the nicknames of the clients connected
	 *					to the current server.
	 */
	public void setClientList(final String[] clients) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() { m_clientList.setListData(clients); }
		});
	}

	/**
	 * Get the current encryption key.
	 * @returns - the key inputted by the user
	 */
	public final String getCryptKey() {
		return m_cryptKey.getText();
	}

	/**
	 * Print text to the chat output box.
	 * @param text - a string to be printed.
	 */
	public void print(final String text) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {  
				m_text += text;
				// Here you can chage the overall look of the chat output.
				// Also if you don't want HTML remove all markup code here.
				m_output.setText( "<html><head><title>Chat</title></head><body><font face=verdana size=3>" + m_text + "</font></body></html>" );			
			}
		});	
	}

	/**
	 * Print text to the chat output pane,
	 * also end the text with a line break.
	 * @param text - a string to be printed.
	 */
	public void println(final String text) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() { print(text + "<br>"); }
		});	
	}

	/**
	 * Clear the chat output pane.
	 */
	public void clear() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {  
				m_text = "";
				print("");
			}
		});	
	}

	/* Constructor. Edit this to change look and functionality. */
	private ChatGUI(String name, ChatInterface ci) {
		super(name);
		final ChatGUI gui = this;
		
		
		m_interface = ci;
		m_interface.setGUI(this);

		// Create tabs
		m_tabs = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.WRAP_TAB_LAYOUT);
		m_nameServerPanel = new JPanel();
  		m_chatPanel = new JPanel();

      // Create name server panel content
      m_nsToolBar = new JToolBar();
      m_nsHost = new JTextField(25);
      m_nsPort = new JTextField(7);
      m_nsHostText = new JLabel("Host");
      m_nsPortText = new JLabel("Port");
      m_nsConnectBtn = new JButton("Connect");
      m_nickname = new JTextField(10);
//      m_nicknameText = new JLabel("Nickname");
      m_nsScroll = new JScrollPane(
		  ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
		  ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
      m_serverList = new JList();
      m_serverConnectPanel = new JPanel();
//		m_nickname = new JTextField(10);
//      m_nicknameText = new JLabel("Nickname");
      m_serverConnectBtn = new JButton("Connect");

		// Create chat panel content
      m_chatToolBar = new JToolBar();
		m_encrypt = new JCheckBox("Encrpt");
		m_compress = new JCheckBox("Compress");
      m_cryptKey = new JTextField(10);
      m_cryptKeyText = new JLabel("Key");
		m_disconnectBtn = new JButton("Disconnect");
		m_output = new JEditorPane("text/html",""); // Change here if you don't want HTML
		m_scrollOutput = new JScrollPane(
		  ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
		  ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		m_clientList = new JList();
		m_scrollClientList = new JScrollPane(
		  ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
		  ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		m_sendPanel = new JPanel();
		m_input = new JTextField();
		m_sendBtn = new JButton("Send");

		// Connect tabs
		this.setLayout(new BorderLayout());
		this.getContentPane().add(m_tabs, BorderLayout.CENTER);
		if (m_useNameServer)  m_tabs.addTab("Name Server", m_nameServerPanel);
		else						 m_tabs.addTab("Chat Server", m_nameServerPanel);
		m_tabs.addTab("Chat", m_chatPanel);

		// Connect name server panel components
      m_nameServerPanel.setLayout(new BorderLayout());
      m_nameServerPanel.add(m_nsToolBar, BorderLayout.NORTH);
      if (m_useNameServer) {
         m_nameServerPanel.add(m_nsScroll, BorderLayout.CENTER);
	      m_nameServerPanel.add(m_serverConnectPanel, BorderLayout.SOUTH);
      }
      
      m_nsScroll.getViewport().setView(m_serverList);
      
		m_nsToolBar.setLayout(new FlowLayout(FlowLayout.LEFT));
      m_nsToolBar.add(m_nsHostText);
      m_nsToolBar.add(m_nsHost);
      m_nsToolBar.add(m_nsPortText);
      m_nsToolBar.add(m_nsPort);
//      m_nsToolBar.add(m_nicknameText);
//      m_nsToolBar.add(m_nickname);
  		m_nsToolBar.add(m_nsConnectBtn);

      m_serverConnectPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
      m_serverConnectPanel.add(m_serverConnectBtn);

		// Connect chat panel components
	   m_chatPanel.setLayout(new BorderLayout());
      m_chatPanel.add(m_sendPanel, BorderLayout.SOUTH);
      m_chatPanel.add(m_chatToolBar, BorderLayout.NORTH);
      m_chatPanel.add(m_scrollOutput, BorderLayout.CENTER);
      m_chatPanel.add(m_scrollClientList, BorderLayout.EAST);

      m_chatToolBar.setLayout(new FlowLayout(FlowLayout.LEFT));
      m_chatToolBar.add(m_disconnectBtn);

      m_scrollOutput.getViewport().setView(m_output);
      m_scrollClientList.getViewport().setView(m_clientList);

      m_sendPanel.setLayout(new BorderLayout());
		m_sendPanel.add(m_input, BorderLayout.CENTER);
		m_sendPanel.add(m_sendBtn, BorderLayout.EAST);

		// Set properties
		m_nsToolBar.setFloatable(false);
		m_serverList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
//		m_nickname.setText("Karl Popper");
		
		m_tabs.setEnabledAt(1,false);
		m_chatToolBar.setFloatable(false);
		m_cryptKey.setText("foobar");
		m_output.setEditable(false);
		m_clientList.setFixedCellWidth(150);
		m_clientList.setFocusable(false);

		this.setLocation(30,30);
		this.setFocusable(true);
		this.setSize(800, 600);
		this.setMinimumSize(new Dimension(800,600));
		this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		this.setVisible(true);

		// Add listeners
//		m_serverConnectBtn
//		m_nsConnectBtn
		m_nsConnectBtn.addActionListener( new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				m_interface.connectChatServer(m_nsHost.getText(), m_nsPort.getText(), m_nickname.getText());
				
			}
		});

		m_disconnectBtn.addActionListener( new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				m_interface.disconnectChatServer();
				
			}
		});

		m_sendBtn.addActionListener( new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				m_interface.send(m_input.getText());
				m_input.setText("");
			}
		});
		
		m_input.addKeyListener( new KeyAdapter() {
			public void keyReleased(KeyEvent event) {
				if (event.getKeyCode() == KeyEvent.VK_ENTER) {
					m_sendBtn.doClick();
				}
			}
		});
	}

}
